Load packages
library(tidyverse)
library(readxl)
library(cowplot)
Import data
#Anna's Laptop
#Data <- read_xlsx("~/Desktop/PhysiologyDatabaseVersion5.xlsx", sheet = "T3", na = c("NA", ""))
# Mariana's desktop
#Data <- read_xlsx("/Users/marianaabarcazama/Desktop/Projects/ThermalPerformance/PhysiologyDatabaseVersion5.xlsx", sheet = "T3", na = c("NA", ""))
# Mariana's laptop
#Data <- read_xlsx("/Users/mar/Desktop/Projects/ThermalPerformance/PhysiologyDatabaseVersion5.xlsx", sheet = "T3", na = c("NA", ""))
Remove parasitoids and convert character to factor
unique(Data$status)
Error in unique(Data$status) : object 'Data' not found
Calculate development rate
When all larvae in a treatment die, their development time is “NA”, however their development rate should be “0”. The loop below calculates development rate (1/dt) and assigns 0 to all cases where both survival is 0 and development time is “NA”. There is one case in which development time is less than 1, it was rounded to 1.
fast <- filter(Ana, dt < 1)
Ana <- Ana %>%
mutate(dt = ifelse(dt < 1, ceiling(dt),dt))
sets <- unique(Ana$set)
rates <- tribble(~set, ~temp, ~dr)
rates2 <- tribble(~set, ~temp, ~dr)
output.table <- tibble()
for(i in seq_along(sets)) {
# make a table per set and determine whether it includes dt data
seti <- sets[i]
table <- filter(Ana, set == seti)
suma <- sum(table$dt, na.rm = T)
# if there is dt data
if (suma > 0){
clement <- filter(table, dt > 0) [["temp"]] # temperatures that allow for development
hotlim <- max(clement, na.rm = T) # max temp that permits development
coldlim <- min(clement, na.rm = T) # min temp that permits development
tempes <- unique(table$temp) # each temperature included in set i
# evaluate each temperature of a set
for(ii in 1:length(unique(tempes))){
tempii <- tempes[ii]
# if it is lower than coldlim, dr should be zero
if (table$temp[ii] < coldlim){
dr <- 0
output.row <- cbind(set = seti, temp = tempii, dr = dr)
# if it is higher than hotlim, dr should be zero
} else if (table$temp[ii] > hotlim) {
dr <- 0
output.row <- cbind(set = seti, temp = tempii, dr = dr)
# in all other cases, it should be 1/dt
} else{
dr <- 1/table$dt[ii]
output.row <- cbind(set = seti, temp = tempii, dr = dr)
}
output.table <- rbind(output.table, output.row)
}
# print stuff to make sure loop is working
#cat(seti, " ")
# if there is no development time in that set, dr should be zero
} else {
#cat("set: ", seti, "has no dt \n")
}
}
rates <- output.table
Ana_rates <- left_join(Ana, rates, by = c("set","temp"))
rm(fast, output.row, output.table, rates, rates2, table)
rm(clement, coldlim, dr, hotlim, i, ii, seti, sets, suma, tempes, tempii)
Summary statistics
There are 23 Lepidoptera families in the dataset.
family_sets <- Ana_rates %>%
select(set, family) %>%
distinct() %>%
group_by(family) %>%
summarise(sets = length(unique(set)))
Each family is represented by 3 to 405 sets.
ggplot(family_sets, aes(x = reorder(family, - sets), y = sets)) +
geom_col()+
geom_hline(yintercept = 50)+
geom_hline(yintercept = 25, linetype = 2)+
theme_cowplot()+
xlab("Family")+
coord_flip()

Figure 1. Number of sets per family, lines indicate 25 and 50 counts
species <- Ana_rates %>%
select(family, sp) %>%
distinct() %>%
group_by(family) %>%
summarise(sp_count = length(unique(sp))) %>%
arrange(sp_count)
ggplot(species, aes(x = reorder(family, - sp_count), y = sp_count)) +
geom_col()+
geom_hline(yintercept = 10, linetype = 2)+
geom_hline(yintercept = 5, linetype = 1)+
theme_cowplot()+
xlab("Family")+
ylab("Species")+
coord_flip()

Figure 2. Number of species per family, lines indicate 5 and 10 species counts.
lifestage_sets <- Ana_rates %>%
select(set, lifestage) %>%
distinct() %>%
group_by(lifestage) %>%
summarise(sets = length(unique(set))) %>%
arrange(sets)
ggplot(lifestage_sets, aes(x = reorder(lifestage, sets), y = sets)) +
geom_col()+
geom_hline(yintercept = 50)+
geom_hline(yintercept = 25, linetype = 2)+
theme_cowplot()+
xlab("Life stage")+
coord_flip()

Figure 3. Number of sets measuring each lifestage.
lifestage_sets_2 <- Ana_rates %>%
select(set, lifestage) %>%
distinct() %>%
group_by(lifestage) %>%
summarise(sets = length(unique(set))) %>%
arrange(sets) %>%
filter(sets > 4)
ggplot(lifestage_sets_2, aes(x = reorder(lifestage, sets), y = sets)) +
geom_col()+
geom_hline(yintercept = 50)+
geom_hline(yintercept = 25, linetype = 2)+
theme_cowplot()+
xlab("Life stage")+
coord_flip()

Figure 4. Number of sets per lifestage (only lifestages that have at least 5 sets). Lines at 50 and 25.
Sets with both development rate and survival
interval_sets <- Ana_rates %>%
group_by(set) %>%
mutate(dr_sum = sum(dr),
n_temps = length(unique(temp)),
validcount = sum(!is.na(dt)),
validcount_s = sum(!is.na(survival))) %>%
filter(n_temps > 3, dr_sum > 0, validcount > 3, validcount_s > 3)
interval_set_list <- unique(interval_sets$set)
interval <- Ana_rates %>% filter(set %in% interval_set_list)
main_stages <- Ana_rates %>%
filter(lifestage == "egg"|lifestage == "larva"|lifestage == "pupa")
main_stages_list <- unique(main_stages$lifestage)
inter <- interval %>% filter(lifestage %in% main_stages_list)
inter$lifestage <- factor(inter$lifestage)
There are 240 sets with both survival and development time data, from 57 families and 21 lifestages.
For the three main lifestages (egg, larva, pupa), there are 137 sets with both survival and development time data, from 51 species.
Upper Limit Exploration
At the upper thermal ranges contained in the dataset, we are interested in seeing whether we capture the ranges at which survival/development rate begin to decrease. The function below (is.rise) can be applied to development rate and to survival data. It returns a table with 6 columns: just.rise: TURE/FALSE. TRUE for curves missing the range at which performance decreases. ntemp: number of temperature treatments colds: number of temperature treatments below optimum hots: number of temperature treatments above optimum opts: number of temperatures that maximize performance (it’s common to observe multiple survival optima) response: dr/survival
is.rise <- function(table, response){
ta <- select(table, temp, response) # make a 2 column table
if(nrow(ta) == sum(is.na(ta[,2]))){ # this is to discard sets with only NA # values
print("No data")
}else{
# get:
# maximum performance
p.large <- max(ta[,2], na.rm = T)
# maximum temperature
t.max <- max(ta[,1], na.rm = T)
# coldest temperature that maximizes performance
t.large <- filter(ta, ta[,2] == p.large)[["temp"]][[1]]
# hotest temperature that maximizes performance (eg, survival can be 1 at
# multiple temperatures)
t.largemax <- max(t.large, na.rm = T)
# temperatures below the coldest optimum
colds <- filter(ta, ta[,1] < t.large)
# temperature above the hotest optimum
hots <- filter(ta, temp > t.largemax)
# temperatures that maximize performance
opts <- filter(ta, ta[,2] == p.large)
#output table
output <- tibble(just.rise = t.max == t.largemax, # TRUE for curves missing fall
ntemp = nrow(ta), # number of temperature treatments
colds = nrow(colds), # number of temps below optimum
hots = nrow(hots), # number of temps above optimum
opts = nrow(opts), # number of optimum temps
response = response) # dr or survival
output
}
}
Function to determine if minimum development time occurs at the highest temperature
# Is development time minimum at the highest temperature? ---------------------------------------------------------------
where.min.dt <- function(table){
ta <- select(table, temp, dt) # make a 2 column table
if(nrow(ta) == sum(is.na(ta[,2]))){ # this is to discard sets with only NA # values
print("No data")
}else{
# get:
# minimum development time
min.dt <- min(ta$dt, na.rm = T)
# maximum temperature
t.max <- max(ta$temp, na.rm = T)
min.dt.t <- tail(filter(ta, dt == min.dt)[["temp"]])
#output table
output <- tibble(is.min.at.hottest = t.max == min.dt.t) # TRUE when min at hotest
output
}
}
Calculate the number of sets where the maximum survival is not at the highest measured temp
This code applies the function above to each set, the result is a tibble of tables
qualitycheck <- inter %>%
group_by(set) %>%
nest() %>%
mutate(quality_dr = map2(data, "dr", is.rise),
quality_sur = map2(data, "survival", is.rise),
is.min.dt.at.max.t = map(data, where.min.dt))
Get only the quality metrics by set
Qmetrics <- select(qualitycheck, set, quality_dr, quality_sur, is.min.dt.at.max.t) %>%
unnest( cols = quality_dr, quality_sur, is.min.dt.at.max.t)
unnest() has a new interface. See ?unnest for details.
Try `df %>% unnest(c(quality_dr, quality_sur, is.min.dt.at.max.t))`, with `mutate()` if needed
Number of sets where the minimum development time is not at the highest measured temp: 109
There are 137 sets and most of them 114 report a fall in development time as temperature increases.
There are 148 sets in which the highest survival is not at the highest temperature
What are the most popular temperature treatments implemented?
ggplot(inter, aes(x = temp))+
geom_bar()+
theme_cowplot()+
facet_grid(~lifestage)

Figure 5. Frequency of temperature treatments in “inter” data set by life stage. The most popular temperature treatments are 15, 20, 25, 30, and 35.
Exploratory Graphs
These graphs represent some early data exploration, using the subset of the data that contains both survival and development time for the three main lifestages (egg, larva, pupa).
drhist <- ggplot(Qmetrics, aes(x = hots))+
geom_histogram() +
xlab("temps above dr optimum")+
theme_cowplot()
survivalhist <- ggplot(Qmetrics, aes(x = hots1))+
geom_histogram() +
xlab("temps above survival optimum")+
theme_cowplot()
plot_grid(drhist, survivalhist)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Figure 6. Histograms showing most sets in the “inter” subset include at least one temperature above the dr optimum and multple above the survival optimum
Scale development time
Function to extract longest development time by set and create a new column with scaled development time. s_dt = 1 - (dt/maxdt).
scale.dt <- function(table){
maxdt <- max(table$dt, na.rm = T)
table$s_dt <- 1 - (table$dt/maxdt)
table
}
Apply the function to each set and add s_dt column (scaled dt)
inter <- inter %>%
group_by(set) %>%
nest() %>%
mutate(s_dt = map(data, scale.dt)) %>%
unnest(cols = s_dt) %>%
select(-data)
Plot to check that s_dt was calculated properly
ggplot(filter(inter, set == 941|set == 1179| set == 3), aes(x = dt, y = s_dt, col = factor(set)))+
geom_point()+
scale_color_viridis_d()+
theme_cowplot()

dt: development time, s_dt, scaled development time (0 for longest)
egg <- inter[inter$lifestage == "egg", ]
egg$set <- factor(egg$set)
larva <- inter[inter$lifestage == "larva", ]
larva$set <- factor(larva$set)
pupa <- inter[inter$lifestage == "pupa", ]
pupa$set <- factor(pupa$set)
Graph the survival data vs. temperature within each lifestage, with each set as a line, faceted by family
ggplot(data = egg, aes(x = temp, y = survival, color = set, group = set)) +
geom_line() +
facet_wrap(~family) +
labs(x = "Temperature", y = "Survival (percentage)", title = "Egg Survival")

Figure 5. Egg survival at a range of temperatures, faceted by family.
ggplot(data = larva, aes(x = temp, y = survival, color = set, group = set)) +
geom_line() +
facet_wrap(~family) +
labs(x = "Temperature", y = "Survival (percentage)", title = "Larval Survival")

Figure 6. Larval survival at a range of temperatures, faceted by family.
ggplot(data = pupa, aes(x = temp, y = survival, color = set, group = set)) +
geom_line() +
facet_wrap(~family) +
labs(x = "Temperature", y = "Survival (percentage)", title = "Pupal Survival")

Figure 7. Pupal survival at a range of temperatures, faceted by family.
Graph the development time data vs. temperature within each lifestage, with each set as a line, faceted by family
ggplot(data = egg, aes(x = temp, y = dt, color = set, group = set)) +
geom_line() +
facet_wrap(~family) +
labs(x = "Temperature", y = "Development time (days)", title = "Egg Development Time")

Figure 8. Egg development time at a range of temperatures, faceted by family.
ggplot(data = larva, aes(x = temp, y = dt, color = set, group = set)) +
geom_line() +
facet_wrap(~family) +
labs(x = "Temperature", y = "Development time (days)", title = "Larval Development Time")

Figure 9. Larval development time at a range of temperatures, faceted by family.
ggplot(data = pupa, aes(x = temp, y = dt, color = set, group = set)) +
geom_line() +
facet_wrap(~family) +
labs(x = "Temperature", y = "Development time (days)", title = "Pupal Development Time")

Figure 10. Pupal development time at a range of temperatures, faceted by family.
Other exploratory graphs
Noctuids - an example of family-specific graphs
ggplot(data = filter(egg, family == "Noctuidae"), aes(x = temp, y = s_dt, color = set, group = set)) +
geom_line() +
geom_line(data = filter(egg, family == "Noctuidae"), mapping = aes(x = temp, y = survival/100, color = set, group = set), linetype = 2)+
facet_wrap(~sp) +
labs(x = "Temperature", y = "Scaled dt / Survival (dashed)", title = "Noctuid Egg Development and Survival")

Figure 11. Egg development rate and survival in the Noctuidae family, faceted by species.
ggplot(data = filter(larva, family == "Noctuidae"), aes(x = temp, y = s_dt, color = set, group = set)) +
geom_line() +
geom_line(data = filter(larva, family == "Noctuidae"), mapping = aes(x = temp, y = survival/100, color = set, group = set), linetype = 2)+
facet_wrap(~sp) +
labs(x = "Temperature", y = "Scaled dev time / Survival (dashed)", title = "Noctuid Larval Development and Survival")

Figure 12. Larval development rate and survival in the Noctuidae family, faceted by species.
ggplot(data = filter(pupa, family == "Noctuidae"), aes(x = temp, y = s_dt, color = set, group = set)) +
geom_line() +
geom_line(data = filter(pupa, family == "Noctuidae"), mapping = aes(x = temp, y = survival/100, color = set, group = set), linetype = 2)+
facet_wrap(~sp) +
labs(x = "Temperature", y = "Scaled dev time / Survival (dashed)", title = "Noctuid Pupal Development and Survival")

Figure 13. Pupal development rate and survival in the Noctuidae family, faceted by species.
Cummulative survival graphs
For studies that report survival of eggs, larvae and pupa, make graphs of cummulative survival:
# get ids of sets that report survival in all three life stages
egg <- filter(inter, lifestage == "egg", survival >= 0)
egg$set <- factor(egg$set)
larva <- filter(inter, lifestage == "larva", survival >= 1)
larva$set <- factor(larva$set)
pupa <- filter(inter, lifestage == "pupa", survival >= 1)
pupa$set <- factor(pupa$set)
egg_ids <- tibble(id = unique(egg$id))
larva_ids <- tibble(id = unique(larva$id))
pupa_ids <- tibble(id = unique(pupa$id))
fullstudies1 <- intersect(egg_ids,larva_ids)
fullstudies <- intersect(fullstudies1,pupa_ids)
# the new table "ontosurvival" contains only those sets
ontosurvival <- inter %>% filter(id %in% fullstudies$id)
ontosurvival$stagenum <- ifelse(ontosurvival$lifestage == "egg", 1, ifelse(ontosurvival$lifestage == "larva",2, 3))
Making a graph with cumulative survival
Here, I calculate cumulative/total suvival at each temp for each set and attempt to plot it.
head(ontosurvival)
combsurvival <- ontosurvival[, c("set", "id", "sp", "lifestage", "temp", "survival", "stagenum")]
LS0tCnRpdGxlOiAiQ29tcGlsYXRpb24gb2YgTGVwaWRvcHRlcmEgdGhlcm1hbCBwZXJmb3JtYW5jZSBjdXJ2ZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyBMb2FkIHBhY2thZ2VzCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoY293cGxvdCkKYGBgCiAKIyBJbXBvcnQgZGF0YQpgYGB7cn0KI0FubmEncyBMYXB0b3AKI0RhdGEgPC0gcmVhZF94bHN4KCJ+L0Rlc2t0b3AvUGh5c2lvbG9neURhdGFiYXNlVmVyc2lvbjUueGxzeCIsIHNoZWV0ID0gIlQzIiwgbmEgPSBjKCJOQSIsICIiKSkKYGBgCgpgYGB7cn0KIyBNYXJpYW5hJ3MgZGVza3RvcAojRGF0YSA8LSByZWFkX3hsc3goIi9Vc2Vycy9tYXJpYW5hYWJhcmNhemFtYS9EZXNrdG9wL1Byb2plY3RzL1RoZXJtYWxQZXJmb3JtYW5jZS9QaHlzaW9sb2d5RGF0YWJhc2VWZXJzaW9uNS54bHN4Iiwgc2hlZXQgPSAiVDMiLCBuYSA9IGMoIk5BIiwgIiIpKSAKCmBgYAoKYGBge3J9CiMgTWFyaWFuYSdzIGxhcHRvcAojRGF0YSA8LSByZWFkX3hsc3goIi9Vc2Vycy9tYXIvRGVza3RvcC9Qcm9qZWN0cy9UaGVybWFsUGVyZm9ybWFuY2UvUGh5c2lvbG9neURhdGFiYXNlVmVyc2lvbjUueGxzeCIsIHNoZWV0ID0gIlQzIiwgbmEgPSBjKCJOQSIsICIiKSkgCmBgYAoKUmVtb3ZlIHBhcmFzaXRvaWRzIGFuZCBjb252ZXJ0IGNoYXJhY3RlciB0byBmYWN0b3IKYGBge3J9CnVuaXF1ZShEYXRhJHN0YXR1cykKQW5hIDwtIERhdGFbRGF0YSRzdGF0dXMgIT0gInBhcmFzaXRvaWQiLF0Kcm0oRGF0YSkKCiMgY29udmVydCBjaGFyYWN0ZXIgdG8gZmFjdG9yCkFuYSA8LSBBbmEgJT4lCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgZmFjdG9yKQpgYGAKCiMjIENhbGN1bGF0ZSBkZXZlbG9wbWVudCByYXRlCldoZW4gYWxsIGxhcnZhZSBpbiBhIHRyZWF0bWVudCBkaWUsIHRoZWlyIGRldmVsb3BtZW50IHRpbWUgaXMgIk5BIiwgaG93ZXZlcgp0aGVpciBkZXZlbG9wbWVudCByYXRlIHNob3VsZCBiZSAiMCIuIFRoZSBsb29wIGJlbG93IGNhbGN1bGF0ZXMgZGV2ZWxvcG1lbnQgcmF0ZSAoMS9kdCkgYW5kIGFzc2lnbnMgMCB0byBhbGwgY2FzZXMgd2hlcmUgYm90aCBzdXJ2aXZhbCBpcyAwIGFuZCBkZXZlbG9wbWVudCB0aW1lIGlzICJOQSIuClRoZXJlIGlzIG9uZSBjYXNlIGluIHdoaWNoIGRldmVsb3BtZW50IHRpbWUgaXMgbGVzcyB0aGFuIDEsIGl0IHdhcyByb3VuZGVkIHRvIDEuCgpgYGB7cn0KZmFzdCA8LSBmaWx0ZXIoQW5hLCBkdCA8IDEpCkFuYSA8LSBBbmEgJT4lIAogIG11dGF0ZShkdCA9IGlmZWxzZShkdCA8IDEsIGNlaWxpbmcoZHQpLGR0KSkKICAKCnNldHMgPC0gdW5pcXVlKEFuYSRzZXQpIApyYXRlcyA8LSB0cmliYmxlKH5zZXQsIH50ZW1wLCB+ZHIpCnJhdGVzMiA8LSB0cmliYmxlKH5zZXQsIH50ZW1wLCB+ZHIpCm91dHB1dC50YWJsZSA8LSB0aWJibGUoKQoKZm9yKGkgaW4gc2VxX2Fsb25nKHNldHMpKSB7CiAgCiAgIyBtYWtlIGEgdGFibGUgcGVyIHNldCBhbmQgZGV0ZXJtaW5lIHdoZXRoZXIgaXQgaW5jbHVkZXMgZHQgZGF0YQogIHNldGkgPC0gc2V0c1tpXQogIHRhYmxlIDwtIGZpbHRlcihBbmEsIHNldCA9PSBzZXRpKQogIHN1bWEgPC0gc3VtKHRhYmxlJGR0LCBuYS5ybSA9IFQpCiAgCiAgIyBpZiB0aGVyZSBpcyBkdCBkYXRhCiAgaWYgKHN1bWEgPiAwKXsgCiAgICAKICAgIGNsZW1lbnQgPC0gZmlsdGVyKHRhYmxlLCBkdCA+IDApIFtbInRlbXAiXV0gIyB0ZW1wZXJhdHVyZXMgdGhhdCBhbGxvdyBmb3IgZGV2ZWxvcG1lbnQKICAgIGhvdGxpbSA8LSBtYXgoY2xlbWVudCwgbmEucm0gPSBUKSAjIG1heCB0ZW1wIHRoYXQgcGVybWl0cyBkZXZlbG9wbWVudAogICAgY29sZGxpbSA8LSBtaW4oY2xlbWVudCwgbmEucm0gPSBUKSAjIG1pbiB0ZW1wIHRoYXQgcGVybWl0cyBkZXZlbG9wbWVudAogICAgdGVtcGVzIDwtIHVuaXF1ZSh0YWJsZSR0ZW1wKSAjIGVhY2ggdGVtcGVyYXR1cmUgaW5jbHVkZWQgaW4gc2V0IGkKICAgIAogICAgIyBldmFsdWF0ZSBlYWNoIHRlbXBlcmF0dXJlIG9mIGEgc2V0CiAgICBmb3IoaWkgaW4gMTpsZW5ndGgodW5pcXVlKHRlbXBlcykpKXsKICAgICAgCiAgICAgIHRlbXBpaSA8LSB0ZW1wZXNbaWldCiAgICAgIAogICAgICAjIGlmIGl0IGlzIGxvd2VyIHRoYW4gY29sZGxpbSwgZHIgc2hvdWxkIGJlIHplcm8KICAgICAgaWYgKHRhYmxlJHRlbXBbaWldIDwgY29sZGxpbSl7CiAgICAgICAgZHIgPC0gMAogICAgICBvdXRwdXQucm93IDwtIGNiaW5kKHNldCA9IHNldGksIHRlbXAgPSB0ZW1waWksIGRyID0gZHIpCiAgICAgIAogICAgICAjIGlmIGl0IGlzIGhpZ2hlciB0aGFuIGhvdGxpbSwgZHIgc2hvdWxkIGJlIHplcm8gIAogICAgICB9IGVsc2UgaWYgKHRhYmxlJHRlbXBbaWldID4gaG90bGltKSB7CiAgICAgICAgCiAgICAgICAgZHIgPC0gMAogICAgICBvdXRwdXQucm93IDwtIGNiaW5kKHNldCA9IHNldGksIHRlbXAgPSB0ZW1waWksIGRyID0gZHIpCiAgICAgIAogICAgICAjIGluIGFsbCBvdGhlciBjYXNlcywgaXQgc2hvdWxkIGJlIDEvZHQKICAgICAgfSBlbHNlewogICAgICAgIGRyIDwtIDEvdGFibGUkZHRbaWldCiAgICAgICAgb3V0cHV0LnJvdyA8LSBjYmluZChzZXQgPSBzZXRpLCB0ZW1wID0gdGVtcGlpLCBkciA9IGRyKQogICAgICB9CiAgICAgIAogICAgICBvdXRwdXQudGFibGUgPC0gcmJpbmQob3V0cHV0LnRhYmxlLCBvdXRwdXQucm93KQogICAgfQogICAgCiAgICAjIHByaW50IHN0dWZmIHRvIG1ha2Ugc3VyZSBsb29wIGlzIHdvcmtpbmcKICAgICNjYXQoc2V0aSwgIiAiKQogICAgCiAgICAKICAjIGlmIHRoZXJlIGlzIG5vIGRldmVsb3BtZW50IHRpbWUgaW4gdGhhdCBzZXQsIGRyIHNob3VsZCBiZSB6ZXJvCiAgICB9IGVsc2UgewogICAgI2NhdCgic2V0OiAiLCBzZXRpLCAiaGFzIG5vIGR0IFxuIikKICB9CiAgCn0KCnJhdGVzIDwtIG91dHB1dC50YWJsZQoKQW5hX3JhdGVzIDwtIGxlZnRfam9pbihBbmEsIHJhdGVzLCBieSA9IGMoInNldCIsInRlbXAiKSkKCnJtKGZhc3QsIG91dHB1dC5yb3csIG91dHB1dC50YWJsZSwgcmF0ZXMsIHJhdGVzMiwgdGFibGUpCnJtKGNsZW1lbnQsIGNvbGRsaW0sIGRyLCBob3RsaW0sIGksIGlpLCBzZXRpLCBzZXRzLCBzdW1hLCB0ZW1wZXMsIHRlbXBpaSkKCmBgYAoKIyBTdW1tYXJ5IHN0YXRpc3RpY3MKVGhlcmUgYXJlIGByIGxlbmd0aCh1bmlxdWUoQW5hX3JhdGVzJGZhbWlseSkpYCBMZXBpZG9wdGVyYSBmYW1pbGllcyBpbiB0aGUgZGF0YXNldC4KYGBge3J9CmZhbWlseV9zZXRzIDwtICBBbmFfcmF0ZXMgJT4lCiAgc2VsZWN0KHNldCwgZmFtaWx5KSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoZmFtaWx5KSAlPiUgCiAgc3VtbWFyaXNlKHNldHMgPSBsZW5ndGgodW5pcXVlKHNldCkpKQpgYGAKCkVhY2ggZmFtaWx5IGlzIHJlcHJlc2VudGVkIGJ5IGByIG1pbihmYW1pbHlfc2V0cyRzZXRzKWAgdG8gYHIgbWF4KGZhbWlseV9zZXRzJHNldHMpYCBzZXRzLiAKCmBgYHtyfQpnZ3Bsb3QoZmFtaWx5X3NldHMsIGFlcyh4ID0gcmVvcmRlcihmYW1pbHksIC0gc2V0cyksIHkgPSBzZXRzKSkgKwogIGdlb21fY29sKCkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNTApKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDI1LCBsaW5ldHlwZSA9IDIpKwogIHRoZW1lX2Nvd3Bsb3QoKSsKICB4bGFiKCJGYW1pbHkiKSsKICBjb29yZF9mbGlwKCkKYGBgCgpGaWd1cmUgMS4gTnVtYmVyIG9mIHNldHMgcGVyIGZhbWlseSwgbGluZXMgaW5kaWNhdGUgMjUgYW5kIDUwIGNvdW50cwpgYGB7cn0Kc3BlY2llcyA8LSAgQW5hX3JhdGVzICU+JQogIHNlbGVjdChmYW1pbHksIHNwKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoZmFtaWx5KSAlPiUgCiAgc3VtbWFyaXNlKHNwX2NvdW50ID0gbGVuZ3RoKHVuaXF1ZShzcCkpKSAlPiUgCiAgYXJyYW5nZShzcF9jb3VudCkKCmdncGxvdChzcGVjaWVzLCBhZXMoeCA9IHJlb3JkZXIoZmFtaWx5LCAtIHNwX2NvdW50KSwgeSA9IHNwX2NvdW50KSkgKwogIGdlb21fY29sKCkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTAsIGxpbmV0eXBlID0gMikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNSwgbGluZXR5cGUgPSAxKSsKICB0aGVtZV9jb3dwbG90KCkrCiAgeGxhYigiRmFtaWx5IikrCiAgeWxhYigiU3BlY2llcyIpKwogIGNvb3JkX2ZsaXAoKQpgYGAKCkZpZ3VyZSAyLiBOdW1iZXIgb2Ygc3BlY2llcyBwZXIgZmFtaWx5LCBsaW5lcyBpbmRpY2F0ZSA1IGFuZCAxMCBzcGVjaWVzIGNvdW50cy4KCgpgYGB7cn0KbGlmZXN0YWdlX3NldHMgPC0gIEFuYV9yYXRlcyAlPiUKICBzZWxlY3Qoc2V0LCBsaWZlc3RhZ2UpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBncm91cF9ieShsaWZlc3RhZ2UpICU+JSAKICBzdW1tYXJpc2Uoc2V0cyA9IGxlbmd0aCh1bmlxdWUoc2V0KSkpICU+JSAKICBhcnJhbmdlKHNldHMpCgpnZ3Bsb3QobGlmZXN0YWdlX3NldHMsIGFlcyh4ID0gcmVvcmRlcihsaWZlc3RhZ2UsICBzZXRzKSwgeSA9IHNldHMpKSArCiAgZ2VvbV9jb2woKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMjUsIGxpbmV0eXBlID0gMikrCiAgdGhlbWVfY293cGxvdCgpKwogIHhsYWIoIkxpZmUgc3RhZ2UiKSsKIAogIGNvb3JkX2ZsaXAoKQpgYGAKCgpGaWd1cmUgMy4gTnVtYmVyIG9mIHNldHMgbWVhc3VyaW5nIGVhY2ggbGlmZXN0YWdlLgoKYGBge3J9CmxpZmVzdGFnZV9zZXRzXzIgPC0gIEFuYV9yYXRlcyAlPiUKICBzZWxlY3Qoc2V0LCBsaWZlc3RhZ2UpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBncm91cF9ieShsaWZlc3RhZ2UpICU+JSAKICBzdW1tYXJpc2Uoc2V0cyA9IGxlbmd0aCh1bmlxdWUoc2V0KSkpICU+JSAKICBhcnJhbmdlKHNldHMpICU+JSAKICBmaWx0ZXIoc2V0cyA+IDQpCgpnZ3Bsb3QobGlmZXN0YWdlX3NldHNfMiwgYWVzKHggPSByZW9yZGVyKGxpZmVzdGFnZSwgIHNldHMpLCB5ID0gc2V0cykpICsKICBnZW9tX2NvbCgpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDUwKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAyNSwgbGluZXR5cGUgPSAyKSsKICB0aGVtZV9jb3dwbG90KCkrCiAgeGxhYigiTGlmZSBzdGFnZSIpKwogIAogIGNvb3JkX2ZsaXAoKQpgYGAKRmlndXJlIDQuIE51bWJlciBvZiBzZXRzIHBlciBsaWZlc3RhZ2UgKG9ubHkgbGlmZXN0YWdlcyB0aGF0IGhhdmUgYXQgbGVhc3QgNSBzZXRzKS4gTGluZXMgYXQgNTAgYW5kIDI1LgoKIyBTZXRzIHdpdGggYm90aCBkZXZlbG9wbWVudCByYXRlIGFuZCBzdXJ2aXZhbAoKYGBge3J9CmludGVydmFsX3NldHMgPC0gQW5hX3JhdGVzICU+JSAKICBncm91cF9ieShzZXQpICU+JSAKICAgCiAgbXV0YXRlKGRyX3N1bSA9IHN1bShkciksIAogICAgICAgICBuX3RlbXBzID0gbGVuZ3RoKHVuaXF1ZSh0ZW1wKSksIAogICAgICAgICB2YWxpZGNvdW50ID0gc3VtKCFpcy5uYShkdCkpLCAKICAgICAgICAgdmFsaWRjb3VudF9zID0gc3VtKCFpcy5uYShzdXJ2aXZhbCkpKSAlPiUgCiAgZmlsdGVyKG5fdGVtcHMgPiAzLCBkcl9zdW0gPiAwLCB2YWxpZGNvdW50ID4gMywgdmFsaWRjb3VudF9zID4gMykKCmludGVydmFsX3NldF9saXN0IDwtIHVuaXF1ZShpbnRlcnZhbF9zZXRzJHNldCkgCgppbnRlcnZhbCA8LSBBbmFfcmF0ZXMgJT4lIGZpbHRlcihzZXQgJWluJSBpbnRlcnZhbF9zZXRfbGlzdCkKCm1haW5fc3RhZ2VzIDwtIEFuYV9yYXRlcyAlPiUgCiAgZmlsdGVyKGxpZmVzdGFnZSA9PSAiZWdnInxsaWZlc3RhZ2UgPT0gImxhcnZhInxsaWZlc3RhZ2UgPT0gInB1cGEiKQptYWluX3N0YWdlc19saXN0IDwtIHVuaXF1ZShtYWluX3N0YWdlcyRsaWZlc3RhZ2UpCmludGVyIDwtIGludGVydmFsICU+JSBmaWx0ZXIobGlmZXN0YWdlICVpbiUgbWFpbl9zdGFnZXNfbGlzdCkgCmludGVyJGxpZmVzdGFnZSA8LSBmYWN0b3IoaW50ZXIkbGlmZXN0YWdlKQoKYGBgClRoZXJlIGFyZSBgciBsZW5ndGgodW5pcXVlKGludGVydmFsJHNldCkpYCBzZXRzIHdpdGggYm90aCBzdXJ2aXZhbCBhbmQKZGV2ZWxvcG1lbnQgdGltZSBkYXRhLCBmcm9tIGByIGxlbmd0aCh1bmlxdWUoaW50ZXJ2YWwkc3ApKWAgZmFtaWxpZXMgYW5kCmByIGxlbmd0aCh1bmlxdWUoaW50ZXJ2YWwkbGlmZXN0YWdlKSlgIGxpZmVzdGFnZXMuIAoKRm9yIHRoZSB0aHJlZSBtYWluIGxpZmVzdGFnZXMgKGVnZywgbGFydmEsIHB1cGEpLCB0aGVyZSBhcmUgYHIgbGVuZ3RoKHVuaXF1ZShpbnRlciRzZXQpKWAgc2V0cyB3aXRoIGJvdGggc3Vydml2YWwgYW5kCmRldmVsb3BtZW50IHRpbWUgZGF0YSwgZnJvbSBgciBsZW5ndGgodW5pcXVlKGludGVyJHNwKSlgIHNwZWNpZXMuCgojIFVwcGVyIExpbWl0IEV4cGxvcmF0aW9uIApBdCB0aGUgdXBwZXIgdGhlcm1hbCByYW5nZXMgY29udGFpbmVkIGluIHRoZSBkYXRhc2V0LCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBzZWVpbmcgd2hldGhlciB3ZSBjYXB0dXJlIHRoZSByYW5nZXMgYXQgd2hpY2ggc3Vydml2YWwvZGV2ZWxvcG1lbnQgcmF0ZSBiZWdpbiB0byBkZWNyZWFzZS4gClRoZSBmdW5jdGlvbiBiZWxvdyAoaXMucmlzZSkgY2FuIGJlIGFwcGxpZWQgdG8gZGV2ZWxvcG1lbnQgcmF0ZSBhbmQgdG8gc3Vydml2YWwgZGF0YS4gSXQgcmV0dXJucyBhIHRhYmxlIHdpdGggNiBjb2x1bW5zOgpqdXN0LnJpc2U6IFRVUkUvRkFMU0UuIFRSVUUgZm9yIGN1cnZlcyBtaXNzaW5nIHRoZSByYW5nZSBhdCB3aGljaCBwZXJmb3JtYW5jZSBkZWNyZWFzZXMuCm50ZW1wOiBudW1iZXIgb2YgdGVtcGVyYXR1cmUgdHJlYXRtZW50cwpjb2xkczogbnVtYmVyIG9mIHRlbXBlcmF0dXJlIHRyZWF0bWVudHMgYmVsb3cgb3B0aW11bQpob3RzOiBudW1iZXIgb2YgdGVtcGVyYXR1cmUgdHJlYXRtZW50cyBhYm92ZSBvcHRpbXVtCm9wdHM6IG51bWJlciBvZiB0ZW1wZXJhdHVyZXMgdGhhdCBtYXhpbWl6ZSBwZXJmb3JtYW5jZSAoaXQncyBjb21tb24gdG8gb2JzZXJ2ZSBtdWx0aXBsZSBzdXJ2aXZhbCBvcHRpbWEpCnJlc3BvbnNlOiBkci9zdXJ2aXZhbAoKYGBge3J9CmlzLnJpc2UgPC0gZnVuY3Rpb24odGFibGUsIHJlc3BvbnNlKXsKICB0YSA8LSBzZWxlY3QodGFibGUsIHRlbXAsIHJlc3BvbnNlKSAjIG1ha2UgYSAyIGNvbHVtbiB0YWJsZQogIAogIGlmKG5yb3codGEpID09IHN1bShpcy5uYSh0YVssMl0pKSl7ICMgdGhpcyBpcyB0byBkaXNjYXJkIHNldHMgd2l0aCBvbmx5IE5BICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdmFsdWVzCiAgICBwcmludCgiTm8gZGF0YSIpCiAgfWVsc2V7CiAgICAKICAgICMgZ2V0OgogICAgIyBtYXhpbXVtIHBlcmZvcm1hbmNlCiAgICBwLmxhcmdlIDwtIG1heCh0YVssMl0sIG5hLnJtID0gVCkgCiAgICAjIG1heGltdW0gdGVtcGVyYXR1cmUKICAgIHQubWF4IDwtIG1heCh0YVssMV0sIG5hLnJtID0gVCkKICAgICMgY29sZGVzdCB0ZW1wZXJhdHVyZSB0aGF0IG1heGltaXplcyBwZXJmb3JtYW5jZQogICAgdC5sYXJnZSA8LSBmaWx0ZXIodGEsIHRhWywyXSA9PSBwLmxhcmdlKVtbInRlbXAiXV1bWzFdXQogICAgIyBob3Rlc3QgdGVtcGVyYXR1cmUgdGhhdCBtYXhpbWl6ZXMgcGVyZm9ybWFuY2UgKGVnLCBzdXJ2aXZhbCBjYW4gYmUgMSBhdCAKICAgICMgbXVsdGlwbGUgdGVtcGVyYXR1cmVzKQogICAgdC5sYXJnZW1heCA8LSBtYXgodC5sYXJnZSwgbmEucm0gPSBUKQogICAgIyB0ZW1wZXJhdHVyZXMgYmVsb3cgdGhlIGNvbGRlc3Qgb3B0aW11bQogICAgY29sZHMgPC0gZmlsdGVyKHRhLCB0YVssMV0gPCB0LmxhcmdlKQogICAgIyB0ZW1wZXJhdHVyZSBhYm92ZSB0aGUgaG90ZXN0IG9wdGltdW0KICAgIGhvdHMgPC0gZmlsdGVyKHRhLCB0ZW1wID4gdC5sYXJnZW1heCkKICAgICMgdGVtcGVyYXR1cmVzIHRoYXQgbWF4aW1pemUgcGVyZm9ybWFuY2UKICAgIG9wdHMgPC0gZmlsdGVyKHRhLCB0YVssMl0gPT0gcC5sYXJnZSkKICAgIAogICAgI291dHB1dCB0YWJsZQogICAgb3V0cHV0IDwtIHRpYmJsZShqdXN0LnJpc2UgPSAgdC5tYXggPT0gdC5sYXJnZW1heCwgIyBUUlVFIGZvciBjdXJ2ZXMgbWlzc2luZyBmYWxsCiAgICAgICAgICAgICAgICAgICAgIG50ZW1wID0gbnJvdyh0YSksICMgbnVtYmVyIG9mIHRlbXBlcmF0dXJlIHRyZWF0bWVudHMKICAgICAgICAgICAgICAgICAgICAgY29sZHMgPSBucm93KGNvbGRzKSwgIyBudW1iZXIgb2YgdGVtcHMgYmVsb3cgb3B0aW11bQogICAgICAgICAgICAgICAgICAgICBob3RzID0gbnJvdyhob3RzKSwgIyBudW1iZXIgb2YgdGVtcHMgYWJvdmUgb3B0aW11bQogICAgICAgICAgICAgICAgICAgICBvcHRzID0gbnJvdyhvcHRzKSwgIyBudW1iZXIgb2Ygb3B0aW11bSB0ZW1wcwogICAgICAgICAgICAgICAgICAgICByZXNwb25zZSA9IHJlc3BvbnNlKSAjIGRyIG9yIHN1cnZpdmFsCiAgICBvdXRwdXQKICB9Cn0KYGBgCgogRnVuY3Rpb24gdG8gZGV0ZXJtaW5lIGlmIG1pbmltdW0gZGV2ZWxvcG1lbnQgdGltZSBvY2N1cnMgYXQgdGhlIGhpZ2hlc3QgdGVtcGVyYXR1cmUKYGBge3J9CiMgSXMgZGV2ZWxvcG1lbnQgdGltZSBtaW5pbXVtIGF0IHRoZSBoaWdoZXN0IHRlbXBlcmF0dXJlPyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kd2hlcmUubWluLmR0IDwtIGZ1bmN0aW9uKHRhYmxlKXsKICB0YSA8LSBzZWxlY3QodGFibGUsIHRlbXAsIGR0KSAjIG1ha2UgYSAyIGNvbHVtbiB0YWJsZQogIAogIGlmKG5yb3codGEpID09IHN1bShpcy5uYSh0YVssMl0pKSl7ICMgdGhpcyBpcyB0byBkaXNjYXJkIHNldHMgd2l0aCBvbmx5IE5BICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdmFsdWVzCiAgICBwcmludCgiTm8gZGF0YSIpCiAgfWVsc2V7CiAgICAKICAgICMgZ2V0OgogICAgIyBtaW5pbXVtIGRldmVsb3BtZW50IHRpbWUKICAgIG1pbi5kdCA8LSBtaW4odGEkZHQsIG5hLnJtID0gVCkgCiAgICAjIG1heGltdW0gdGVtcGVyYXR1cmUKICAgIHQubWF4IDwtIG1heCh0YSR0ZW1wLCBuYS5ybSA9IFQpCiAgICAKICAgIG1pbi5kdC50IDwtIHRhaWwoZmlsdGVyKHRhLCBkdCA9PSBtaW4uZHQpW1sidGVtcCJdXSkKICAgIAogICAgI291dHB1dCB0YWJsZQogICAgb3V0cHV0IDwtIHRpYmJsZShpcy5taW4uYXQuaG90dGVzdCA9ICB0Lm1heCA9PSBtaW4uZHQudCkgIyBUUlVFIHdoZW4gbWluIGF0IGhvdGVzdAogICAgb3V0cHV0CiAgfQp9CmBgYAoKIyMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2Ygc2V0cyB3aGVyZSB0aGUgbWF4aW11bSBzdXJ2aXZhbCBpcyBub3QgYXQgdGhlIGhpZ2hlc3QgbWVhc3VyZWQgdGVtcApUaGlzIGNvZGUgYXBwbGllcyB0aGUgZnVuY3Rpb24gYWJvdmUgdG8gZWFjaCBzZXQsIHRoZSByZXN1bHQgaXMgYSB0aWJibGUgb2YgdGFibGVzCmBgYHtyfQpxdWFsaXR5Y2hlY2sgPC0gaW50ZXIgJT4lIAogIGdyb3VwX2J5KHNldCkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKHF1YWxpdHlfZHIgPSBtYXAyKGRhdGEsICJkciIsIGlzLnJpc2UpLCAKICAgICAgICAgcXVhbGl0eV9zdXIgPSBtYXAyKGRhdGEsICJzdXJ2aXZhbCIsIGlzLnJpc2UpLCAKICAgICAgICAgaXMubWluLmR0LmF0Lm1heC50ID0gbWFwKGRhdGEsIHdoZXJlLm1pbi5kdCkpCmBgYAoKR2V0IG9ubHkgdGhlIHF1YWxpdHkgbWV0cmljcyBieSBzZXQKYGBge3J9ClFtZXRyaWNzIDwtIHNlbGVjdChxdWFsaXR5Y2hlY2ssIHNldCwgcXVhbGl0eV9kciwgcXVhbGl0eV9zdXIsIGlzLm1pbi5kdC5hdC5tYXgudCkgJT4lIAogIHVubmVzdCggY29scyA9IHF1YWxpdHlfZHIsIHF1YWxpdHlfc3VyLCBpcy5taW4uZHQuYXQubWF4LnQpCmBgYAoKCiMjIE51bWJlciBvZiBzZXRzIHdoZXJlIHRoZSBtaW5pbXVtIGRldmVsb3BtZW50IHRpbWUgaXMgbm90IGF0IHRoZSBoaWdoZXN0IG1lYXN1cmVkIHRlbXA6IGByIHN1bShRbWV0cmljcyRpcy5taW4uYXQuaG90dGVzdCA9PSBGQUxTRSlgClRoZXJlIGFyZSBgciBsZW5ndGgodW5pcXVlKFFtZXRyaWNzJHNldCkpYCBzZXRzIGFuZCBtb3N0IG9mIHRoZW0gIGByIHN1bShRbWV0cmljcyRqdXN0LnJpc2UgPT0gRkFMU0UpYCByZXBvcnQgYSBmYWxsIGluIGRldmVsb3BtZW50IHRpbWUgYXMgdGVtcGVyYXR1cmUgaW5jcmVhc2VzLgoKVGhlcmUgYXJlIGByIHN1bShRbWV0cmljcyRqdXN0LnJpc2UxID09IEZBTFNFKWAgc2V0cyBpbiB3aGljaCB0aGUgaGlnaGVzdCBzdXJ2aXZhbCBpcyBub3QgYXQgdGhlIGhpZ2hlc3QgdGVtcGVyYXR1cmUKCiMgV2hhdCBhcmUgdGhlIG1vc3QgcG9wdWxhciB0ZW1wZXJhdHVyZSB0cmVhdG1lbnRzIGltcGxlbWVudGVkPwoKYGBge3J9CmdncGxvdChpbnRlciwgYWVzKHggPSB0ZW1wKSkrCiAgZ2VvbV9iYXIoKSsKICB0aGVtZV9jb3dwbG90KCkrCiAgZmFjZXRfZ3JpZCh+bGlmZXN0YWdlKQpgYGAKRmlndXJlIDUuIEZyZXF1ZW5jeSBvZiB0ZW1wZXJhdHVyZSB0cmVhdG1lbnRzIGluICJpbnRlciIgZGF0YSBzZXQgYnkgbGlmZSBzdGFnZS4gClRoZSBtb3N0IHBvcHVsYXIgdGVtcGVyYXR1cmUgdHJlYXRtZW50cyBhcmUgMTUsIDIwLCAyNSwgMzAsIGFuZCAzNS4KCiMgRXhwbG9yYXRvcnkgR3JhcGhzClRoZXNlIGdyYXBocyByZXByZXNlbnQgc29tZSBlYXJseSBkYXRhIGV4cGxvcmF0aW9uLCB1c2luZyB0aGUgc3Vic2V0IG9mIHRoZSBkYXRhIHRoYXQgY29udGFpbnMgYm90aCBzdXJ2aXZhbCBhbmQgZGV2ZWxvcG1lbnQgdGltZSBmb3IgdGhlIHRocmVlIG1haW4gbGlmZXN0YWdlcyAoZWdnLCBsYXJ2YSwgcHVwYSkuIApgYGB7cn0KZHJoaXN0IDwtIGdncGxvdChRbWV0cmljcywgYWVzKHggPSBob3RzKSkrCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgeGxhYigidGVtcHMgYWJvdmUgZHIgb3B0aW11bSIpKwogIHRoZW1lX2Nvd3Bsb3QoKQpzdXJ2aXZhbGhpc3QgPC0gZ2dwbG90KFFtZXRyaWNzLCBhZXMoeCA9IGhvdHMxKSkrCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgeGxhYigidGVtcHMgYWJvdmUgc3Vydml2YWwgb3B0aW11bSIpKwogIHRoZW1lX2Nvd3Bsb3QoKQpwbG90X2dyaWQoZHJoaXN0LCBzdXJ2aXZhbGhpc3QpCgpgYGAKRmlndXJlIDYuIEhpc3RvZ3JhbXMgc2hvd2luZyBtb3N0IHNldHMgaW4gdGhlICJpbnRlciIgc3Vic2V0IGluY2x1ZGUgYXQgbGVhc3Qgb25lIHRlbXBlcmF0dXJlIGFib3ZlIHRoZSBkciBvcHRpbXVtIGFuZCBtdWx0cGxlIGFib3ZlIHRoZSBzdXJ2aXZhbCBvcHRpbXVtCgojIFNjYWxlIGRldmVsb3BtZW50IHRpbWUKRnVuY3Rpb24gdG8gZXh0cmFjdCBsb25nZXN0IGRldmVsb3BtZW50IHRpbWUgYnkgc2V0IGFuZCBjcmVhdGUgYSBuZXcgY29sdW1uIHdpdGggc2NhbGVkIGRldmVsb3BtZW50IHRpbWUuIApzX2R0ID0gMSAtIChkdC9tYXhkdCkuCmBgYHtyfQpzY2FsZS5kdCA8LSBmdW5jdGlvbih0YWJsZSl7CiAgbWF4ZHQgPC0gbWF4KHRhYmxlJGR0LCBuYS5ybSA9IFQpCiAgdGFibGUkc19kdCA8LSAxIC0gKHRhYmxlJGR0L21heGR0KQogIHRhYmxlCn0KYGBgCgoKQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIGVhY2ggc2V0IGFuZCBhZGQgc19kdCBjb2x1bW4gKHNjYWxlZCBkdCkKYGBge3J9CmludGVyIDwtIGludGVyICU+JSAKICBncm91cF9ieShzZXQpICU+JSAKICBuZXN0KCkgJT4lIAogIG11dGF0ZShzX2R0ID0gbWFwKGRhdGEsIHNjYWxlLmR0KSkgJT4lIAogIHVubmVzdChjb2xzID0gc19kdCkgJT4lIAogIHNlbGVjdCgtZGF0YSkKYGBgCgpQbG90IHRvIGNoZWNrIHRoYXQgc19kdCB3YXMgY2FsY3VsYXRlZCBwcm9wZXJseQpgYGB7cn0KZ2dwbG90KGZpbHRlcihpbnRlciwgc2V0ID09IDk0MXxzZXQgPT0gMTE3OXwgc2V0ID09IDMpLCBhZXMoeCA9IGR0LCB5ID0gc19kdCwgY29sID0gZmFjdG9yKHNldCkpKSsKICBnZW9tX3BvaW50KCkrCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkrCiAgdGhlbWVfY293cGxvdCgpCmBgYApkdDogZGV2ZWxvcG1lbnQgdGltZSwgc19kdCwgc2NhbGVkIGRldmVsb3BtZW50IHRpbWUgKDAgZm9yIGxvbmdlc3QpCgpgYGB7cn0KZWdnIDwtIGludGVyW2ludGVyJGxpZmVzdGFnZSA9PSAiZWdnIiwgXQplZ2ckc2V0IDwtIGZhY3RvcihlZ2ckc2V0KQpsYXJ2YSA8LSBpbnRlcltpbnRlciRsaWZlc3RhZ2UgPT0gImxhcnZhIiwgXQpsYXJ2YSRzZXQgPC0gZmFjdG9yKGxhcnZhJHNldCkKcHVwYSA8LSBpbnRlcltpbnRlciRsaWZlc3RhZ2UgPT0gInB1cGEiLCBdCnB1cGEkc2V0IDwtIGZhY3RvcihwdXBhJHNldCkKYGBgCgojIyBHcmFwaCB0aGUgc3Vydml2YWwgZGF0YSB2cy4gdGVtcGVyYXR1cmUgd2l0aGluIGVhY2ggbGlmZXN0YWdlLCB3aXRoIGVhY2ggc2V0IGFzIGEgbGluZSwgZmFjZXRlZCBieSBmYW1pbHkgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBlZ2csIGFlcyh4ID0gdGVtcCwgeSA9IHN1cnZpdmFsLCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5mYW1pbHkpICsgCiAgbGFicyh4ID0gIlRlbXBlcmF0dXJlIiwgeSA9ICJTdXJ2aXZhbCAocGVyY2VudGFnZSkiLCB0aXRsZSA9ICJFZ2cgU3Vydml2YWwiKQpgYGAKRmlndXJlIDUuIEVnZyBzdXJ2aXZhbCBhdCBhIHJhbmdlIG9mIHRlbXBlcmF0dXJlcywgZmFjZXRlZCBieSBmYW1pbHkuIAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGxhcnZhLCBhZXMoeCA9IHRlbXAsIHkgPSBzdXJ2aXZhbCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+ZmFtaWx5KSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU3Vydml2YWwgKHBlcmNlbnRhZ2UpIiwgdGl0bGUgPSAiTGFydmFsIFN1cnZpdmFsIikKYGBgCkZpZ3VyZSA2LiBMYXJ2YWwgc3Vydml2YWwgYXQgYSByYW5nZSBvZiB0ZW1wZXJhdHVyZXMsIGZhY2V0ZWQgYnkgZmFtaWx5LiAKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBwdXBhLCBhZXMoeCA9IHRlbXAsIHkgPSBzdXJ2aXZhbCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+ZmFtaWx5KSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU3Vydml2YWwgKHBlcmNlbnRhZ2UpIiwgdGl0bGUgPSAiUHVwYWwgU3Vydml2YWwiKQpgYGAKRmlndXJlIDcuIFB1cGFsIHN1cnZpdmFsIGF0IGEgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzLCBmYWNldGVkIGJ5IGZhbWlseS4gCgoKIyMgR3JhcGggdGhlIGRldmVsb3BtZW50IHRpbWUgZGF0YSB2cy4gdGVtcGVyYXR1cmUgd2l0aGluIGVhY2ggbGlmZXN0YWdlLCB3aXRoIGVhY2ggc2V0IGFzIGEgbGluZSwgZmFjZXRlZCBieSBmYW1pbHkKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGVnZywgYWVzKHggPSB0ZW1wLCB5ID0gZHQsIGNvbG9yID0gc2V0LCBncm91cCA9IHNldCkpICsgCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmZhbWlseSkgKyAKICBsYWJzKHggPSAiVGVtcGVyYXR1cmUiLCB5ID0gIkRldmVsb3BtZW50IHRpbWUgKGRheXMpIiwgdGl0bGUgPSAiRWdnIERldmVsb3BtZW50IFRpbWUiKQpgYGAKRmlndXJlIDguIEVnZyBkZXZlbG9wbWVudCB0aW1lIGF0IGEgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzLCBmYWNldGVkIGJ5IGZhbWlseS4gCgoKYGBge3J9CmdncGxvdChkYXRhID0gbGFydmEsIGFlcyh4ID0gdGVtcCwgeSA9IGR0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5mYW1pbHkpICsgCiAgbGFicyh4ID0gIlRlbXBlcmF0dXJlIiwgeSA9ICJEZXZlbG9wbWVudCB0aW1lIChkYXlzKSIsIHRpdGxlID0gIkxhcnZhbCBEZXZlbG9wbWVudCBUaW1lIikKYGBgCkZpZ3VyZSA5LiBMYXJ2YWwgZGV2ZWxvcG1lbnQgdGltZSBhdCBhIHJhbmdlIG9mIHRlbXBlcmF0dXJlcywgZmFjZXRlZCBieSBmYW1pbHkuIAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHB1cGEsIGFlcyh4ID0gdGVtcCwgeSA9IGR0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5mYW1pbHkpICsgCiAgbGFicyh4ID0gIlRlbXBlcmF0dXJlIiwgeSA9ICJEZXZlbG9wbWVudCB0aW1lIChkYXlzKSIsIHRpdGxlID0gIlB1cGFsIERldmVsb3BtZW50IFRpbWUiKQpgYGAKRmlndXJlIDEwLiBQdXBhbCBkZXZlbG9wbWVudCB0aW1lIGF0IGEgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzLCBmYWNldGVkIGJ5IGZhbWlseS4gCgojIyBPdGhlciBleHBsb3JhdG9yeSBncmFwaHMKCiMjIyBOb2N0dWlkcyAtIGFuIGV4YW1wbGUgb2YgZmFtaWx5LXNwZWNpZmljIGdyYXBocwoKYGBge3J9CmdncGxvdChkYXRhID0gZmlsdGVyKGVnZywgZmFtaWx5ID09ICJOb2N0dWlkYWUiKSwgYWVzKHggPSB0ZW1wLCB5ID0gc19kdCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBmaWx0ZXIoZWdnLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBtYXBwaW5nID0gYWVzKHggPSB0ZW1wLCB5ID0gc3Vydml2YWwvMTAwLCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpLCBsaW5ldHlwZSA9IDIpKwogIGZhY2V0X3dyYXAofnNwKSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU2NhbGVkIGR0IC8gU3Vydml2YWwgKGRhc2hlZCkiLCB0aXRsZSA9ICJOb2N0dWlkIEVnZyBEZXZlbG9wbWVudCBhbmQgU3Vydml2YWwiKQpgYGAKRmlndXJlIDExLiBFZ2cgZGV2ZWxvcG1lbnQgcmF0ZSBhbmQgc3Vydml2YWwgaW4gdGhlIE5vY3R1aWRhZSBmYW1pbHksIGZhY2V0ZWQgYnkgc3BlY2llcy4gCgoKYGBge3J9CmdncGxvdChkYXRhID0gZmlsdGVyKGxhcnZhLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBhZXMoeCA9IHRlbXAsIHkgPSBzX2R0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpbHRlcihsYXJ2YSwgZmFtaWx5ID09ICJOb2N0dWlkYWUiKSwgbWFwcGluZyA9IGFlcyh4ID0gdGVtcCwgeSA9IHN1cnZpdmFsLzEwMCwgY29sb3IgPSBzZXQsIGdyb3VwID0gc2V0KSwgbGluZXR5cGUgPSAyKSsKICBmYWNldF93cmFwKH5zcCkgKyAKICBsYWJzKHggPSAiVGVtcGVyYXR1cmUiLCB5ID0gIlNjYWxlZCBkZXYgdGltZSAvIFN1cnZpdmFsIChkYXNoZWQpIiwgdGl0bGUgPSAiTm9jdHVpZCBMYXJ2YWwgRGV2ZWxvcG1lbnQgYW5kIFN1cnZpdmFsIikKYGBgCkZpZ3VyZSAxMi4gTGFydmFsIGRldmVsb3BtZW50IHJhdGUgYW5kIHN1cnZpdmFsIGluIHRoZSBOb2N0dWlkYWUgZmFtaWx5LCBmYWNldGVkIGJ5IHNwZWNpZXMuIAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGZpbHRlcihwdXBhLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBhZXMoeCA9IHRlbXAsIHkgPSBzX2R0LCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpKSArIAogIGdlb21fbGluZSgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGZpbHRlcihwdXBhLCBmYW1pbHkgPT0gIk5vY3R1aWRhZSIpLCBtYXBwaW5nID0gYWVzKHggPSB0ZW1wLCB5ID0gc3Vydml2YWwvMTAwLCBjb2xvciA9IHNldCwgZ3JvdXAgPSBzZXQpLCBsaW5ldHlwZSA9IDIpKwogIGZhY2V0X3dyYXAofnNwKSArIAogIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSIsIHkgPSAiU2NhbGVkIGRldiB0aW1lIC8gU3Vydml2YWwgKGRhc2hlZCkiLCB0aXRsZSA9ICJOb2N0dWlkIFB1cGFsIERldmVsb3BtZW50IGFuZCBTdXJ2aXZhbCIpCmBgYApGaWd1cmUgMTMuIFB1cGFsIGRldmVsb3BtZW50IHJhdGUgYW5kIHN1cnZpdmFsIGluIHRoZSBOb2N0dWlkYWUgZmFtaWx5LCBmYWNldGVkIGJ5IHNwZWNpZXMuIAoKIyBDdW1tdWxhdGl2ZSBzdXJ2aXZhbCBncmFwaHMKRm9yIHN0dWRpZXMgdGhhdCByZXBvcnQgc3Vydml2YWwgb2YgZWdncywgbGFydmFlIGFuZCBwdXBhLCBtYWtlIGdyYXBocyBvZiBjdW1tdWxhdGl2ZSBzdXJ2aXZhbDoKIApgYGB7cn0KIyBnZXQgaWRzIG9mIHNldHMgdGhhdCByZXBvcnQgc3Vydml2YWwgaW4gYWxsIHRocmVlIGxpZmUgc3RhZ2VzCmVnZyA8LSBmaWx0ZXIoaW50ZXIsIGxpZmVzdGFnZSA9PSAiZWdnIiwgc3Vydml2YWwgPj0gMCkKZWdnJHNldCA8LSBmYWN0b3IoZWdnJHNldCkKbGFydmEgPC0gZmlsdGVyKGludGVyLCBsaWZlc3RhZ2UgPT0gImxhcnZhIiwgIHN1cnZpdmFsID49IDEpCmxhcnZhJHNldCA8LSBmYWN0b3IobGFydmEkc2V0KQpwdXBhIDwtIGZpbHRlcihpbnRlciwgbGlmZXN0YWdlID09ICJwdXBhIiwgIHN1cnZpdmFsID49IDEpCnB1cGEkc2V0IDwtIGZhY3RvcihwdXBhJHNldCkKCmVnZ19pZHMgPC0gdGliYmxlKGlkID0gdW5pcXVlKGVnZyRpZCkpCmxhcnZhX2lkcyA8LSB0aWJibGUoaWQgPSB1bmlxdWUobGFydmEkaWQpKQpwdXBhX2lkcyA8LSB0aWJibGUoaWQgPSB1bmlxdWUocHVwYSRpZCkpCgpmdWxsc3R1ZGllczEgPC0gaW50ZXJzZWN0KGVnZ19pZHMsbGFydmFfaWRzKQpmdWxsc3R1ZGllcyA8LSBpbnRlcnNlY3QoZnVsbHN0dWRpZXMxLHB1cGFfaWRzKQojIHRoZSBuZXcgdGFibGUgIm9udG9zdXJ2aXZhbCIgY29udGFpbnMgb25seSB0aG9zZSBzZXRzCm9udG9zdXJ2aXZhbCA8LSBpbnRlciAlPiUgZmlsdGVyKGlkICVpbiUgZnVsbHN0dWRpZXMkaWQpCm9udG9zdXJ2aXZhbCRzdGFnZW51bSA8LSBpZmVsc2Uob250b3N1cnZpdmFsJGxpZmVzdGFnZSA9PSAiZWdnIiwgMSwgaWZlbHNlKG9udG9zdXJ2aXZhbCRsaWZlc3RhZ2UgPT0gImxhcnZhIiwyLCAzKSkKYGBgCgoKIyBNYWtpbmcgYSBncmFwaCB3aXRoIGN1bXVsYXRpdmUgc3Vydml2YWwKSGVyZSwgSSBjYWxjdWxhdGUgY3VtdWxhdGl2ZS90b3RhbCBzdXZpdmFsIGF0IGVhY2ggdGVtcCBmb3IgZWFjaCBzZXQgYW5kIGF0dGVtcHQgdG8gcGxvdCBpdC4gCmBgYHtyfQpoZWFkKG9udG9zdXJ2aXZhbCkKCmNvbWJzdXJ2aXZhbCA8LSBvbnRvc3Vydml2YWxbLCBjKCJzZXQiLCAiaWQiLCAic3AiLCAibGlmZXN0YWdlIiwgInRlbXAiLCAic3Vydml2YWwiLCAic3RhZ2VudW0iKV0KYGBgCgpgYGB7cn0KCgpgYGAKCg==